from civciv import Response
from mako.template import Template
from log import logging
from time import sleep
from chessengine import Board
from sys import exc_info as getExceptionInfo
from db import pg
from pdb import set_trace
import conf, usermn as User, table as Table, piece as Piece, util

def createTable(request,callback,name,location):
  User.updateProfile(User.getId(request),name,location)
  tableId, pieces = Table.create(User.getId(request))
  board = Board(pieces)
  return Response("""%(callback)s(
    %(data)s
  );
  main.engine.environment.getTable().environment.setId(%(tableId)i).listenOpponent();
  %(movement)s
  """%{
    "callback":callback,
    "tableId":tableId,
    "movement":serializeMovement(board),
    "data":"{%s}"%",".join([
      "'%(id)i':{ 'id':%(id)i, 'color':%(color)i, 'value':%(value)i, x:%(x)i, y:%(y)i, 'time':%(last_move_epoch)i }"%piece for piece in pieces
    ])
  })

def form(request,lang=None):
  if lang:
    lang = util.langdict.has_key(lang) and lang or "en"
    request.session["lang"] = lang
  else:
    lang = request.session.has_key("lang") and request.session["lang"] or util.getLang(request)
  return Response(
    Template(filename="%s/template/form.html"%conf.ABS_DIR).render_unicode(
      **{ 
        "lang":lang, 
        'title':util.title[lang], 
        'lang_list':util.langlist, 
        'debug':conf.DEBUG 
      }
    ).encode('utf-8', 'replace'),"text/html"
  )

def joinTable(request,callback,name,location,tableId):
  User.updateProfile(User.getId(request),name,location)
  players = Table.getPlayers(int(tableId))  
  if players[1]:
   return Response("main.engine.environment.getTable().environment.setStatusText('<strong>{0}:</strong>{1}'.format(main.text.error,main.text.joinError),'Red');")
  else:
    pieces, opponent = Table.join(int(tableId),User.getId(request))
    board = Board(pieces)
    return Response("""%(callback)s(%(piece_data)s);
    main.engine.environment.getTable().
    environment.setId(%(table_id)s).
    environment.setOpponent(
    new User().environment.setName('%(user_name)s').environment.setLocation('%(user_location)s')
    );
    %(movement)s"""%{
      "callback":callback,
      "piece_data":"{%s}"%",".join([
        "'%(id)i':{ 'id':%(id)i, 'color':%(color)i, 'value':%(value)i, x:%(x)i, y:%(y)i, 'time':%(last_move_epoch)i }"%piece for piece in pieces
      ]),
      "table_id":tableId,
      "user_name":opponent["name"],
      "user_location":opponent["location"],
      "movement":serializeMovement(board)
    })

def listenMoves(request,callback,tableId,minEpoch):
  response = Response()
  for i in range(15):
    moves = Piece.getByEpoch(int(tableId),User.getId(request),int(minEpoch))
    if moves:
      response.write("%s({%s});"%(callback,",".join([ "'%(id)i':{ 'id':%(id)i, 'color':%(color)i, 'x':%(x)i, 'y':%(y)i, 'value':%(value)i, 'time':%(last_move_epoch)i }"%piece for piece in moves ])))
      board = Board(Piece.getByTableId(int(tableId)))
      response.write(serializeMovement(board))
      if board.winner != -1:
        response.write("main.engine.environment.getTable().close(%i);"%board.winner)
      break
    elif i==14:
      response.write("%s();"%callback)
    
    sleep(1)
  return response
  
def listenOpponent(request,callback,tableId):
  response = Response()
  for i in range(15):
    opponent = Table.getOpponent(int(tableId))
    if opponent:
      response.write("%s(%s);"%(
        callback,
        serializeUser(opponent)
        )
      )
      break
    elif not opponent and i == 14:
      response.write("%s(null);"%callback)
    else:
      User.update(User.getId(request))
      Table.update(int(tableId),0)
      sleep(1)
  return response
  
def listGames(request,callback,serverIndex):
  response = Response()
  
  pg.cursor.execute("SELECT count(id) FROM users WHERE id!=%i AND last_move_epoch>%i"%(User.getId(request),util.unixtime()-conf.CHESS_SERVER["timeout"]))
  playerCount = pg.cursor.fetchone()[0]
  
  if playerCount<conf.CHESS_SERVER["playerLimit"]:
    games = Table.getAvailableTables()
    playerCount+=1
    response.write("""
      %(callback)s(
        %(data)s
      );
    """%{ 
        "callback":callback, 
        "data":"[%s]"%",".join(
          [ "{ id:%(table_id)i, time:%(table_last_move_epoch)i, player:{ name:'%(user_name)s', location:'%(user_location)s' } }"%row for row in games ]
        )
      }
    )
  else:
    response.write("""
      main.engine.element.getServerInfoBox().update('<span class="Error">{0}:</span>{1}'.format(main.text.error,main.text.serverIsFull));
      main.engine.environment.setActiveServer(main.engine.environment.getServer()[%i]);
      """%(int(serverIndex)+1)
    )
  response.write(serverInfo(serverIndex,playerCount))
  User.update(User.getId(request))
  return response

def login(request):
  logging.info(dir(User))
  profile = User.login(request)
  return Response('''
  var user = new User().
  environment.setName('%(name)s').
  environment.setLocation('%(location)s').
  environment.setGamesPlayed(%(games_played)i).
  environment.setGamesWon(%(games_won)i)
  '''%profile)
  
def logout(request):
  request.session.pop("user_id")
  return Response("1")

def move(request,tableId,pieceId,x,y):
  x,y,pieceId,tableId = int(x),int(y),int(pieceId),int(tableId)
  response = Response()
  try:
    pset,players = Piece.getByTableId(tableId),Table.getPlayers(tableId)
    piece = None
    for tpiece in pset:
      if tpiece["id"] == pieceId:
        piece = tpiece
        break

    color = players[piece["color"]]
    
    assert isinstance(piece,dict),"Could not found given piece id."
    assert color==User.getId(request),"Session id and piece don't match."
    assert pset[len(pset)-1]["color"]!=color,"It's not your turn."
    
    board = Board(pset)
    
    if board.square[piece['x']][piece['y']].piece.movement.count( board.square[x][y] ):
      if board.square[x][y].piece:
        Piece.remove( board.square[x][y].piece.pid )
        board.square[x][y].piece = None
      
      value = (piece['value']==1 and ( ( piece['color'] == 0 and y == 7 ) or (piece['color'] == 1 and y == 0) )) and 5 or piece['value']
      
      pobj = board.square[piece['x']][piece['y']].piece
      pobj.symbol = (pobj.symbol[0],value)
      pobj.move( board.square[x][y] )
      
      # castling control
      if piece['value'] == 6 and piece['is_moved'] == False and ( x == 6 or x==2 ) and y == 7*piece['color']:
        rook = board.square[x-(x==2 and 2 or -1)][y].piece
        rook.move(board.square[x==2 and 3 or 5][y])
        Piece.move(rook.pid,rook.square.x,rook.square.y,4)
        response.write( "main.engine.environment.getTable().environment.getPiece()[ %i ].move(%i,%i);"%( rook.pid, rook.square.x, rook.square.y ) )
      
      Piece.move(pieceId,x,y,value)
      
      response.write("main.engine.environment.getTable().environment.setServerTime(%i);"%util.unixtime())
      response.write(serializeMovement(board))
      if board.winner == -1:
        response.write("main.engine.environment.getActiveServer().listen.move();")
      else:
        response.write("main.engine.environment.getTable().close(%i);"%board.winner)
    else:
      raise Piece.IllegalMove,"Movement array of piece-%ix%i doesn't contain square-%ix%i"%(piece['x'],piece['y'],x,y)
  except Piece.IllegalMove:
    exception = getExceptionInfo()
    response.write("main.engine.environment.getTable().environment.getMap()[%i][%i].environment.getPiece().undo(); "%(x,y))
    response.write("main.engine.environment.getTable().environment.setStatusText('<strong>{0}:</strong>{1}.(Exception info: {2}, Line Number: {3} )'.format(main.text.error, main.text.illegalMove,\"%(excInfo)s\",%(excLineNo)i),'Red');"%{ "excInfo":exception[1], "excLineNo":exception[2].tb_lineno })
  except:
    exception = getExceptionInfo()
    response.write("main.engine.environment.getTable().environment.getMap()[%i][%i].environment.getPiece().undo(); "%(x,y))
    response.write("main.engine.environment.getTable().environment.setStatusText('<strong>{0}:</strong>{1}.(Exception info: {2}, Line Number: {3} )'.format(main.text.error, main.text.systemError,\"%(excInfo)s\",%(excLineNo)i),'Red');"%{ "excInfo":exception[1], "excLineNo":exception[2].tb_lineno })

  return response

serializeUser = lambda data: """new User().
    environment.setName('%(name)s').
    environment.setLocation('%(location)s').
    environment.setGamesPlayed(%(games_played)s).
    environment.setGamesWon(%(games_won)s)
  """%data

serializeMovement = lambda board: "".join(
    [ 
      "\nmain.engine.environment.getTable().environment.getMap()[%i][%i].environment.getPiece().environment.setMovement([%s]);"%(
          piece.square.x, piece.square.y, ",".join([
            "main.engine.environment.getTable().environment.getMap()[%i][%i]"%(square.x,square.y) for square in piece.movement 
          ])
      ) for piece in board.piece
    ]
  )

def serverInfo(serverId,playerCount):
  return """
  /*
    player-timeout:%(ptimeout)i
  */
main.engine.environment.getServer()[%(id)s].
environment.setName('%(name)s').
environment.setPlayerLimit(%(playerLimit)i).
environment.setPlayerCount(%(playerCount)i).
environment.setLocation('%(location)s').
environment.setOwnerText('<a href="%(ownerLink)s">%(ownerName)s</a>').
environment.setIsLocked(false).
environment.setTime(%(time)i).
update();"""%{
    "id":serverId, 
    "name":conf.CHESS_SERVER["name"], 
    "playerLimit":conf.CHESS_SERVER["playerLimit"],
    "playerCount":playerCount,
    "location":conf.CHESS_SERVER["location"],
    "ownerName":conf.CHESS_SERVER["ownerName"],
    "ownerLink":conf.CHESS_SERVER["ownerLink"],
    "time":util.unixtime(),
    "ptimeout":(util.unixtime()-conf.CHESS_SERVER["timeout"])
  }
